#include <lcthw/hashmap_algos.h>
#include <lcthw/bstrlib.h>

// settings taken from http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param

const uint32_t FNV_PRIME = 16777619;          // 2^24 + 2^8 + 0x93 = 16777619
const uint32_t FNV_OFFSET_BASIS = 2166136261; // 2^24 + 2^16 + 2^8 + 2^0 = 2166136261

uint32_t Hashmap_fnv1a_hash(void *data)
{
    bstring s = (bstring)data;        // cast data to bstring
    uint32_t hash = FNV_OFFSET_BASIS; // set hash to FNV_OFFSET_BASIS
    int i = 0;

    for (i = 0; i < blength(s); i++)
    {
        hash ^= bchare(s, i, 0); // XOR hash with the ith character of s
        hash *= FNV_PRIME;       // multiply hash by FNV_PRIME
    }

    return hash; // return hash
}

// settings taken from http://en.wikipedia.org/wiki/Adler-32
const int MOD_ADLER = 65521; // largest prime smaller than 2^16

uint32_t Hashmap_adler32_hash(void *data)
{
    bstring s = (bstring)data; // cast data to bstring
    uint32_t a = 1, b = 0;     // set a to 1, b to 0
    int i = 0;

    for (i = 0; i < blength(s); i++)
    {
        a = (a + bchare(s, i, 0)) % MOD_ADLER; // a = (a + ith character of s) % MOD_ADLER
        b = (b + a) % MOD_ADLER;               // b = (b + a) % MOD_ADLER
    }

    return (b << 16) | a; // return (b << 16) | a
}

uint32_t Hashmap_djb_hash(void *data)
{
    bstring s = (bstring)data; // cast data to bstring
    uint32_t hash = 5381;      // set hash to 5381
    int i = 0;

    for (i = 0; i < blength(s); i++)
    {
        hash = ((hash << 5) + hash) + bchare(s, i, 0); // hash = ((hash << 5) + hash) + ith character of s
    }

    return hash; // return hash
}
